// C++可变参数模板的展开方式
#include <bits/stdc++.h>
using namespace std;

template <typename T, typename U, int value>
class SuckType {
 public:
  T a;
  U b;
  SuckType() : a(value), b(value) {}
};

typedef int (*process)(void*);  // 定义了一个返回类型为 int，参数为 void*
                                // 的函数指针类型，名字叫做 process
using process = int (*)(void*);  // 同上, 更加直观

template <typename T>
using NewType = SuckType<int, T, 1>;  // using 合法

// == 获取参数个数
template <typename... Ts>
void magic(Ts... args) {
  std::cout << sizeof...(args) << std::endl;
}
// magic(a,b,c)  // 输出 3

// == 递归展开参数
void FormatPrint_dfs() { std::cout << std::endl; }
template <class T, class... Args>
void FormatPrint_dfs(T first, Args... args) {
  std::cout << first << ", ";
  FormatPrint_dfs(args...);
}

// == 逗号表达式展开 initializer_list
template <class... Args>
void FormatPrint_list(Args... args) {
  (void)std::initializer_list<int>{(std::cout << args << ", ", 0)...};
  printf("\n");
}

// == enable_if
template <std::size_t k = 0, typename tup>
typename std::enable_if<k == std::tuple_size<tup>::value>::type FormatTuple(
    const tup& t) {
  std::cout << std::endl;
}

template <std::size_t k = 0, typename tup>
    typename std::enable_if <
    k<std::tuple_size<tup>::value>::type FormatTuple(const tup& t) {
  std::cout << std::get<k>(t) << ", ";
  FormatTuple<k + 1>(t);
}

template <typename... Args>
void FormatPrint_tuple(Args... args) {
  FormatTuple(std::make_tuple(args...));
}

// == c++17 折叠表达式
template <typename... Args>
void FormatPrint_fold(Args... args) {
  (std::cout << ... << args);
  printf("\n");
}

// == c++17 折叠表达式 format
template <typename T>
string format(T t) {
  std::stringstream ss;
  ss << t << ", ";
  return ss.str();
}

template <typename... Args>
void FormatPrint_format(Args... args) {
  (std::cout << ... << format(args));
  printf("\n");
}

// == c++17 折叠表达式，结合逗号
template <typename... Args>
void FormatPrint_fold_comma(Args... args) {
  (std::cout << ... << (std::cout << args, ", ")) << std::endl;
}

int main(void) {
  FormatPrint_dfs(1, 2, 3.5, "hao");
  FormatPrint_list("good", 2, "hello", 4, 110);
  FormatPrint_tuple(2.5, "kou", 2);
  FormatPrint_fold("effect", 74);
  FormatPrint_format("format", 0);
  FormatPrint_fold_comma("right", 0.4, 7);
  return 0;
}
